#pragma once
#include<iostream>
#include <cppconn/driver.h>
#include <cppconn/connection.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>
#include <cppconn/metadata.h>
#include <cppconn/resultset_metadata.h>
#include <cppconn/exception.h>
#include <cppconn/warning.h>
#include<assert.h>
#include"../comm/log.hpp"
#define DBHOST "tcp://127.0.0.1:3306"
#define USER "cx"
#define PASSWORD "Cx326514.."
namespace Ns_Mod
{
    using namespace std;
    using namespace sql;
    using namespace Ns_Log;
    struct Question//题目结构体
    {
        Question()
        {}
        Question(int id,string qname,string qlevel,string qdisc,string t_limit,string s_limit,string qcue)
        :_id(id),_qname(qname),_qlevel(qlevel),_qdisc(qdisc),_t_limit(t_limit),_s_limit(s_limit),_qcue(qcue)
        {}
        int _id;//题目编号
        string _qname;//题目名称
        string _qlevel;//题目难度
        string _qdisc;//题目描述
        string _t_limit;//时间限制
        string _s_limit;//空间限制
        string _qcue;//思路提示
    };
    struct TestExample//测试用例
    {
        TestExample(const string& std_in,const string& std_out)
        :_stdin(std_in),_stdout(std_out)
        {}
        TestExample()
        {}
        string _stdin;
        string _stdout;
    };
    struct AnswerStatus//用户答题情况
    {
        AnswerStatus(string userid,int questionid,string status,string date,string code)
        :_userid(userid),_questionid(questionid),_status(status),_date(date),_code(code)
        {}
        AnswerStatus()
        {}
        string _userid;
        int _questionid;
        string _status;
        string _date;
        string _code;
    };
    struct UserInformation
    {
        UserInformation()
        {}
        UserInformation(const string& userid,const string& name,const string& gender,const string& age,const string& email,const string& signature)
        :_userid(userid),_name(name),_gender(gender),_age(age),_email(email),_signature(signature)
        {}
        string _userid;
        string _name;
        string _gender;
        string _age;
        string _email;  
        string _signature;
    };
    struct PersonRecord
    {
        //用户id
        //通过题目数量
        //用户签名
        //通过率
        PersonRecord()
        {}
        PersonRecord(const string& name,const string& passed_questions_count,const string& user_signature,const string& passing_probability)
        :_name(name),_passed_questions_count(passed_questions_count),_user_signature(user_signature),_passing_probability(passing_probability)
        {}
        string _name;
        string _passed_questions_count;
        string _user_signature;
        string _passing_probability;
    };
    class Model
    {
    private:
        Driver* _driver;
        Connection* _conn;
        Statement* _stm;
        map<int,Question> _qlist;
        
    public:
        Model()
        :_driver(get_driver_instance()),
        _conn(_driver->connect(DBHOST,USER,PASSWORD)),
        _stm(_conn->createStatement())
        {
            log(INFO,"mysql connect success!");
            log(INFO,"题库加载中...");
            assert(load_questions());
            log(INFO,"题库加载完毕!");
        }
        //获取题目列表的题目数据
        bool get_questions(vector<Question>* vq)
        {
            for(auto q:_qlist)
            {
                (*vq).push_back(q.second);
            }
            if(vq->size()==0)
            return false;
            else
            return true;
        }
        //获取指定单道题目的数据
        bool getquestion(int id,Question* q)
        {
            if(_qlist.find(id)==_qlist.end())
            return false;
            *q=_qlist[id];
            return true;
        }
        //登录对数据的检查
        bool login(const string& userid,const string& password)
        {
            ResultSet *rss;
            rss = _stm->executeQuery("select * from user_password where user_id="+("'"+userid+"'"));
            if(rss->next())
            {
                //比对密码
                string pass=rss->getString("password");
                if(pass==password)
                return true;
            }
            return false;
        }
        //注册对数据的存储
        bool regist(const string& userid,const string& password,const string& gender,
        const string& age,const string& email,const string& name,const string& signature)
        {
            //检查是否已经注册
            ResultSet *rss;
            rss = _stm->executeQuery("select * from user_password where user_id="+("'"+userid+"'"));
            if(rss->next())return false;
            //两张表分别插入
            _stm->execute("insert into user_password values('"+userid+"','"+password+"');");//插入密码表
            bool a=(_stm->getUpdateCount()>=1);//插入username和signature
            _stm->execute("insert into user_information values('"+userid+"','"+name+"','"+gender+"',"+age+",'"+email+"','"+signature+"')");//插入信息表
            bool b=(_stm->getUpdateCount()>=1);
            return a&&b;
        }
        //获取指定一道题的所有测试用例数据
        bool get_test_examples(int qid,vector<TestExample>& tv)
        {
            ResultSet *rss;
            rss = _stm->executeQuery("select * from test_examples where question_id="+to_string(qid));
            if(!rss->next()) return false;
            else
            {
                do
                {
                    string std_in=rss->getString("stdin");
                    string std_out=rss->getString("stdout");
                    tv.push_back(TestExample(std_in,std_out));
                }while (rss->next());
                return true;
            }
        }
        //获取指定用户信息
        bool get_user_information(const string& userid,UserInformation& uf)
        {
            ResultSet *rss;
            rss = _stm->executeQuery("select * from user_information where user_id='"+userid+"'");
            if(!rss->next()) return false;
            else
            {
                string name=rss->getString("user_name");
                string gender=rss->getString("gender");
                string age=rss->getString("age");
                string email=rss->getString("email");
                string user_signature=rss->getString("user_signature");
                uf=UserInformation(userid,name,gender,age,email,user_signature);
                return true;
            }
        }
        //获取排行榜数据
        bool get_rank_data(vector<PersonRecord>& v)
        {
            ResultSet *rss;
            rss = _stm->executeQuery("select user_id,count(*) AS count from question_passed group by user_id order by count DESC");

            if(!rss->next()) return false;
            else
            {
                do
                {
                    string userid=rss->getString("user_id");
                    int count=rss->getInt("count");//有用
                    UserInformation user;
                    if(!get_user_information(userid,user))//查个人信息
                    log(ERROR,"排行榜通过userid查询个人信息失败");
                    v.push_back(PersonRecord(user._name,to_string(count),user._signature,"67%"));
                }while (rss->next());
                return true;
            }
        }
        
        //获取指定用户某道题的所有答题情况
        bool one_question_status(const string& userid ,const string& question_id,vector<AnswerStatus>& ansstat)
        {
            ResultSet *rss;
            //log(DEBUG,"select * from user_answer_status where user_id='"+userid+"' and question_id='"+question_id+"' order by submit_time DESC");
            rss = _stm->executeQuery("select * from user_answer_status where user_id='"+userid+"' and question_id="+question_id+" order by submit_time DESC");
            //log(DEBUG,"ok");
            if(!rss->next())
            return true;
            else
            {
                do
                {
                    string userid=rss->getString("user_id");
                    int questionid=rss->getInt("question_id");
                    string status=rss->getString("status");
                    string date=rss->getString("submit_time");
                    string code=rss->getString("submit_code");
                    ansstat.push_back(AnswerStatus(userid,questionid,status,date,code));
                }while (rss->next());
                return true;
            }
        }
        //获取指定用户所有题目的答题情况
        bool all_question_status(const string& userid ,vector<AnswerStatus>& ansstat)
        {
            ResultSet *rss;
            rss = _stm->executeQuery("select * from user_answer_status where user_id="+userid+" order by submit_time DESC");
            
            if(!rss->next())
            return false;
            else
            {
                do
                {
                    string userid=rss->getString("user_id");
                    int questionid=rss->getInt("question_id");
                    string status=rss->getString("status");
                    string date=rss->getString("submit_time");
                    string code=rss->getString("submit_code");
                    ansstat.push_back(AnswerStatus(userid,questionid,status,date,code));
                }while (rss->next());
                return true;
            }
        }
        //记录指定用户通过了某道题
        bool user_pass_question_update(const string& userid,const string& question_id)
        {
            //插入数据库
            ResultSet *rss;
            rss = _stm->executeQuery("select * from question_passed where user_id="+("'"+userid+"'")+" and question_id="+question_id);
            if(!rss->next())
            {
                //插入
                _stm->execute("insert into question_passed values('"+userid+"',"+question_id+")");
                if(_stm->getUpdateCount()>=1)
                return true;
                else
                return false;
            }
            return true;
        }
        bool user_pass_status_update(const string& userid,const string& question_id,const string& status,const string& code)
        {
            _stm->execute("insert into user_answer_status values('"+userid+"',"+question_id+",'"+status+"',DEFAULT,'"+code+"')");
            if(_stm->getUpdateCount()>=1)
            return true;
            else
            return false;
        }
        bool get_latest_code(const string& userid,const string& question_id,string& code)
        {
            ResultSet *rss;
            //log(DEBUG,"select * from user_answer_status where user_id="+("'"+userid+"'")+" and question_id="+question_id+" ORDER BY submit_time DESC LIMIT 1");
            rss = _stm->executeQuery("select * from user_answer_status where user_id="+("'"+userid+"'")+" and question_id="+question_id+" ORDER BY submit_time DESC LIMIT 1");
            if(!rss->next())
            code="";
            else
            {
                code=rss->getString("submit_code");
            }
            return true;
        }
        ~Model()
        {
            delete _conn;
            delete _stm;
        }
    private:
        bool load_questions()
        {
            _stm->execute("use oj");
            ResultSet *rss;
            rss = _stm->executeQuery("select * from questions");
            if(!rss->next())
            return false;
            else
            {
                do
                {
                    int id = rss->getInt(1);
                    string qname=rss->getString("qname");
                    string qlevel=rss->getString("qlevel");
                    string qdisc=rss->getString("qdisc");
                    string t_limit=rss->getString("t_limit");
                    string s_limit=rss->getString("s_limit");
                    string qcue=rss->getString("qcue");
                    _qlist.insert(make_pair(id,Question(id,qname,qlevel,qdisc,t_limit,s_limit,qcue)));
                }while (rss->next());
                return true;
            }
        }
    };
}
